package search;



import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TreeMap;
import java.util.Vector;
import java.util.Iterator;
import java.io.*;

import index.Balise;
import index.PositionDoc;
import index.Term;
import index.TermFrequency;
import index.TextFilter;
import store.BaseReader;
import store.BaseWriter;
import utils.Similarity;

import java.util.ArrayList;
import java.util.List;

import apple.laf.JRSUIUtils.Tree;

/** Classe permettant de traiter les requetes : recherche des termes dans l'index, calcul des scores des elements
 */
final public class TermQuery {
  
  // vecteur contenant les termes de la requetes (objets Term)
  private Vector terms; 


  
	/**
	* Constructeur : construit le vecteur des termes de la requete
	*/
   public TermQuery(String query,int mode){
   
   terms=new Vector();
   System.out.println("La requete est:"+query);
   TextFilter filter = new TextFilter();
   String[] termstable = filter.filtreTerme(query.toLowerCase());
 
   if (mode ==  2) {
 //lemmatisation
   try {
	termstable = filter.lemmatiserTermes(termstable);
} catch (Throwable e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}
   }
   
   for (int i=0;i<termstable.length;i++) {
	   String[] termpoid = termstable[i].split(":");
	   TermQ monTerme = null;
	   Short un = 1;
	   
	   
	   String mot;
	   mot = termpoid[0].toLowerCase();
		
	   if (mode ==  1) {
	   //on tronque le terme
	   mot = filter.troncTerme(termpoid[0].toLowerCase());
	   }
	   
	   if (termpoid.length <2) monTerme = new TermQ (mot,un);
	   else monTerme = new TermQ (mot,Short.parseShort(termpoid[1]));
	   terms.add(monTerme);
   }
   
  System.out.println("Fin de la requete");
   }

   
   /**
    * Récupère les données de la tables balise
 * @throws SQLException 
    *
    */
   
   public TreeMap<Integer, Balise> initBalises(BaseReader reader) throws SQLException {	
	   TreeMap<Integer, Balise> balises = new TreeMap<Integer, Balise>();
	   balises = reader.getBaliseTable();
	   return balises;
   }
   
   /**
    * Récupère le coeffcient correspondant à une balise
    */
   
   public double getCoeffBalises(TreeMap<Integer, Balise> balises, int idbal) {	
	   double coeff =0 ;
	   
	   if (balises.containsKey(idbal)){
		   coeff = balises.get(idbal).coeff;
	   }
	   return coeff;
   }
   
   /**
    * Récupère la liste de positions correspondant à un document et un terme
    */
   
   public List<PositionDoc> getPosDocTerme(List<PositionDoc> posDoc,  int iddoc) {	
	   List<PositionDoc> posDocList = new ArrayList<PositionDoc>();
	   for (PositionDoc positionDoc : posDoc) {
		   if (positionDoc.doc_id == iddoc) {
			   posDocList.add(positionDoc);
		   }
	}
	   return posDocList;
   }
      
   
  
 
  /**
  * Calcule les scores des documents contenant au moins un terme de la requete
  */
  public TreeMap score(BaseReader reader, int modeScore, int modeModele)
       throws IOException {
 
 TreeMap result = new TreeMap();

 
 TreeMap<Integer, Balise> balises = new TreeMap<Integer, Balise>();
 try {
	balises = initBalises(reader);
} catch (SQLException e1) {
	// TODO Auto-generated catch block
	e1.printStackTrace();
}


// pour chaque terme de la requete   
for (Enumeration e=terms.elements(); e.hasMoreElements();) {
     
	 TermQ myTermQuery = null;
	 Term myTerm = null;
	 List<PositionDoc> myPosList = new ArrayList<PositionDoc>();
	 
     try { 
	 myTermQuery = (TermQ) e.nextElement();
	 System.out.print("recherche dans l'index des doc pour "+myTermQuery.text);
	 myTerm = reader.readTerm(myTermQuery.text);   // on recupère toutes les infos stockées sur ce terme dans l'index           
	 if (myTerm == null) {
			System.out.println("\t -> ce terme n'a pas été trouvé.");
		}
	 
	
	  if (myTerm!=null) {
		  System.out.println("");
		  
		  //On choisi la méthode utilisée
		  if (modeScore == 0) {
			  // Calcul avec TF sans pondération (plus les termes sont présents, plus le document a un score important)
			  System.out.println("mode : TF");
			  result = scoreSansPond(myTerm, myTermQuery,result, modeModele);
		  }
		  else if (modeScore == 1) {
			  System.out.println("mode : Somme Coeff Balise");
			  // Calcul avec Pondération (score = somme (somme des coefficients pour chaque terme))
			  result = scoreCoeffBalise(myTerm, myTermQuery, balises, result, 0, modeModele);
		  }
		  else if (modeScore == 2) {
			  System.out.println("mode : Moyenne Coeff Balise");
			// Calcul avec Pondération (score = somme ( moyennes des coefficients pour chaque terme))
			  result = scoreCoeffBalise(myTerm, myTermQuery, balises, result, 1, modeModele);
		  }
		  else if (modeScore == 3) {
			  System.out.println("mode : TF.IDF");
			// Calcul avec TF.IDF
			  result = scoreIDF(myTerm, myTermQuery, result, modeModele);
		  }
		  //result = scoreIDFCoeff(myTerm, myTermQuery, balises, result);
		}   
      }
    catch (SQLException ex) { 
    System.out.println("Erreur de recuperation du terme ou de calcul du poids");
    System.out.println("SQLException: " + ex.getMessage()); 
    System.out.println("SQLState: " + ex.getSQLState()); 
    System.out.println("VendorError: " + ex.getErrorCode()); 
    }
    
    
    
  
  }
    return result;
  
  } //scorer
  
  
  /**
   * Calcule les scores des documents contenant au moins un terme de la requete
   */
   public TreeMap scoreCoeffBalise(Term myTerm, TermQ myTermQuery, TreeMap<Integer, Balise> balises, TreeMap result, int mode, int modeModele) {
	   //TreeMap result = new TreeMap();
	   List<PositionDoc> myPosList = new ArrayList<PositionDoc>();
	   
	   // pour chaque document contenant le terme, on calcule un score
			for (Iterator it=myTerm.frequency.keySet().iterator();it.hasNext();) {
				    //System.out.println(" test ");
					TermFrequency mafrequence = (TermFrequency) myTerm.frequency.get(it.next());
					
					//myPosList = reader.getPositionDocFromDoc(myTerm.term_id, mafrequence.doc_id);
					myPosList = getPosDocTerme(myTerm.positionDoc, mafrequence.doc_id);
					
					//System.out.println("Liste de positions: "+myPosList);
					double somme = 0;
					double cptCoeff = 0;
					
					
					
					for (int i=0;i<myPosList.size(); i++){
						PositionDoc myPos = myPosList.get(i);
						int myPos_id = myPos.pos_id;
						//double myCoeff = reader.getCoeff(myPos_id);
						double myCoeff = getCoeffBalises(balises, myPos.bal_id);
						
						//System.out.println("coeff: "+myCoeff);
						somme=somme+myCoeff;
						//System.out.println("somme: "+somme);
						cptCoeff++;
					}
					
					double moyenne = 0;
					
					    if (mode == 1)
					    	{moyenne = somme/cptCoeff;}
					    else if(mode == 0) {
					    	moyenne = somme;
					    }
					    //System.out.println("Coeff : "+ moyenne + " - cptCoeff :"+ cptCoeff +" poslistsize:"+ myPosList.size() + "TermFrequency:" + mafrequence.frequency);
					    
					    float weights = Similarity.InnerProd(moyenne, myTermQuery.weigth);
					    
						// si ce document a deja un score, on additionne
						if (!result.containsKey(new Integer(mafrequence.doc_id))) {
						result.put(new Integer(mafrequence.doc_id), new Float(weights));
						//System.out.println("doc: "+mafrequence.doc_id + " score :" +weights);
						}
						// sinon on insere le document
						else {
						Float ancienscore = (Float) result.get(new Integer(mafrequence.doc_id));
						result.remove(new Integer(mafrequence.doc_id));
						
						if (modeModele == 1) {
							result.put(new Integer(mafrequence.doc_id),2*(ancienscore+new Float(weights)));
						}
						else {result.put(new Integer(mafrequence.doc_id),ancienscore+new Float(weights));}
			
				//System.out.println("Ancien score :"+ ancienscore + "Nouveau score:"+ 2*(ancienscore+new Float(weights)));
						}
					//}
			
			}
	   return result;
   }
  
   /**
    * Calcule les scores des documents contenant au moins un terme de la requete
    */
    public TreeMap scoreSansPond(Term myTerm, TermQ myTermQuery, TreeMap result, int modeModele) {
    	//TreeMap result = new TreeMap();
    	
    	if (myTerm!=null) {
    		  
    	       // on pourrait calculer la frequence inverse du terme !!  
    	     
    			// pour chaque document contenant le terme, on calcule un score
    			for (Iterator it=myTerm.frequency.keySet().iterator();it.hasNext();) {
    					TermFrequency mafrequence = (TermFrequency) myTerm.frequency.get(it.next());
    					
    					float weights = Similarity.InnerProd(mafrequence.frequency,	myTermQuery.weigth);
    					// si ce document a deja un score, on additionne
    					if (!result.containsKey(new Integer(mafrequence.doc_id))) {
    					result.put(new Integer(mafrequence.doc_id), new Float(weights));
    					}
    					// sinon on insere le document
    					else {
    					Float ancienscore = (Float) result.get(new Integer(mafrequence.doc_id));
    					result.remove(new Integer(mafrequence.doc_id));
    					if (modeModele == 1) {
							result.put(new Integer(mafrequence.doc_id),2*(ancienscore+new Float(weights)));
						}
						else {result.put(new Integer(mafrequence.doc_id),ancienscore+new Float(weights));}
			
    					}
    			
    			}
    			}
    	return result;
    }
    
    /**
     * Calcule les scores des documents contenant au moins un terme de la requete
     */
     public TreeMap scoreIDF(Term myTerm, TermQ myTermQuery, TreeMap result, int modeModele) {
     	
     	
     	if (myTerm!=null) {
     		  
     	       // on pourrait calculer la frequence inverse du terme !!
     		double tailleCollection = myTerm.frequency.size(); //Nombre de documents contenant le terme
			//System.out.println("taille: "+tailleCollection);
			double idf = (double)Math.log(137.0/tailleCollection); 
     	     
     			// pour chaque document contenant le terme, on calcule un score
     			for (Iterator it=myTerm.frequency.keySet().iterator();it.hasNext();) {
     					TermFrequency mafrequence = (TermFrequency) myTerm.frequency.get(it.next());
     					
     					float weights = Similarity.InnerProd(idf , mafrequence.frequency);
     					
     					// si ce document a deja un score, on additionne
     					if (!result.containsKey(new Integer(mafrequence.doc_id))) {
     					result.put(new Integer(mafrequence.doc_id), new Float(weights));
     					}
     					// sinon on insere le document
     					else {
     					Float ancienscore = (Float) result.get(new Integer(mafrequence.doc_id));
     					result.remove(new Integer(mafrequence.doc_id));
     					if (modeModele == 1) {
							result.put(new Integer(mafrequence.doc_id),2*(ancienscore+new Float(weights)));
						}
						else {result.put(new Integer(mafrequence.doc_id),ancienscore+new Float(weights));}
			
     					}
     			
     			}
     			}
     	return result;
     }
     
     /**
      * Calcule les scores des documents contenant au moins un terme de la requete
      */
      public TreeMap scoreIDFCoeff(Term myTerm, TermQ myTermQuery, TreeMap<Integer, Balise> balises, TreeMap result, int modeModele) {
      	
    	List<PositionDoc> myPosList = new ArrayList<PositionDoc>();
    	  
      	if (myTerm!=null) {
      		  
      	       // on pourrait calculer la frequence inverse du terme !!
      		double tailleCollection = myTerm.frequency.size(); //Nombre de documents contenant le terme
 			//System.out.println("taille: "+tailleCollection);
 			double idf = (double)Math.log(137.0/tailleCollection); 
      	     
      			// pour chaque document contenant le terme, on calcule un score
      			for (Iterator it=myTerm.frequency.keySet().iterator();it.hasNext();) {
      					TermFrequency mafrequence = (TermFrequency) myTerm.frequency.get(it.next());
    					
    					//myPosList = reader.getPositionDocFromDoc(myTerm.term_id, mafrequence.doc_id);
    					myPosList = getPosDocTerme(myTerm.positionDoc, mafrequence.doc_id);
    					
    					//System.out.println("Liste de positions: "+myPosList);
    					double somme = 0;
    					double cptCoeff = 0;
    					
    					
    					
    					for (int i=0;i<myPosList.size(); i++){
    						PositionDoc myPos = myPosList.get(i);
    						int myPos_id = myPos.pos_id;
    						//double myCoeff = reader.getCoeff(myPos_id);
    						double myCoeff = getCoeffBalises(balises, myPos.bal_id);
    						
    						//System.out.println("coeff: "+myCoeff);
    						somme=somme+myCoeff;
    						//System.out.println("somme: "+somme);
    						cptCoeff++;
    					}
    					
    					    double moyenne = somme/cptCoeff;
    						//double moyenne = somme;
    					    //System.out.println("Coeff : "+ moyenne + " - cptCoeff :"+ cptCoeff +" poslistsize:"+ myPosList.size() + "TermFrequency:" + mafrequence.frequency);
    					 
      					
      					double weights = moyenne*idf;
      					//float weights = Similarity.InnerProd( moyenne,idf);
      					
      					// si ce document a deja un score, on additionne
      					if (!result.containsKey(new Integer(mafrequence.doc_id))) {
      					result.put(new Integer(mafrequence.doc_id), new Float(weights));
      					}
      					// sinon on insere le document
      					else {
      					Float ancienscore = (Float) result.get(new Integer(mafrequence.doc_id));
      					result.remove(new Integer(mafrequence.doc_id));
      					if (modeModele == 1) {
							result.put(new Integer(mafrequence.doc_id),2*(ancienscore+new Float(weights)));
						}
						else {result.put(new Integer(mafrequence.doc_id),ancienscore+new Float(weights));}
			
      					}
      			
      			}
      			}
      	return result;
      }
   

} //termQuery.java
